/*
 * Copyright (c) 2023, Your Name
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-xx-xx     Your Name    First version
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
 
 #define DBG_TAG "drv.sdio"
 #define DBG_LVL DBG_LOG
 #include <rtdbg.h>
 
 /* SDIO设备结构体 */
 struct stm32_sdio_device
 {
     struct rt_device parent;
     SD_HandleTypeDef hsd;
     rt_uint32_t sector_size;
     rt_uint32_t sector_count;
 };
 
 static rt_err_t my_rt_sdio_init(rt_device_t dev)
 {
     return RT_EOK;
 }
 
 static rt_err_t my_rt_sdio_open(rt_device_t dev, rt_uint16_t oflag)
 {
     return RT_EOK;
 }
 
 static rt_err_t my_rt_sdio_close(rt_device_t dev)
 {
     return RT_EOK;
 }
 
 static rt_ssize_t my_rt_sdio_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
 {
     struct stm32_sdio_device *sdio = (struct stm32_sdio_device *)dev;
     HAL_StatusTypeDef status;
     
     status = HAL_SD_ReadBlocks(&sdio->hsd, (uint8_t *)buffer, pos, size, 5000);
     if (status != HAL_OK)
     {
         LOG_E("SDIO read failed: %d", status);
         return 0;
     }
     
     /* 等待传输完成 */
     while (HAL_SD_GetCardState(&sdio->hsd) != HAL_SD_CARD_TRANSFER);
     
     return size;
 }
 
 static rt_ssize_t my_rt_sdio_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
 {
     struct stm32_sdio_device *sdio = (struct stm32_sdio_device *)dev;
     HAL_StatusTypeDef status;
     
     status = HAL_SD_WriteBlocks(&sdio->hsd, (uint8_t *)buffer, pos, size, 5000);
     if (status != HAL_OK)
     {
         LOG_E("SDIO write failed: %d", status);
         return 0;
     }
     
     /* 等待传输完成 */
     while (HAL_SD_GetCardState(&sdio->hsd) != HAL_SD_CARD_TRANSFER);
     
     return size;
 }
 
 static rt_err_t my_rt_sdio_control(rt_device_t dev, int cmd, void *args)
 {
     struct stm32_sdio_device *sdio = (struct stm32_sdio_device *)dev;
     
     switch (cmd)
     {
     case RT_DEVICE_CTRL_BLK_GETGEOME:
         {
             struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *)args;
             if (!geometry) return -RT_ERROR;
             
             geometry->bytes_per_sector = sdio->sector_size;
             geometry->block_size = sdio->sector_size;
             geometry->sector_count = sdio->sector_count;
         }
         break;

    case RT_DEVICE_CTRL_BLK_SYNC:  // 添加同步命令
         while (HAL_SD_GetCardState(&sdio->hsd) != HAL_SD_CARD_TRANSFER)
         {
             rt_thread_mdelay(1);
         }
         break;         
         
     default:
         return -RT_ERROR;
     }
     
     return RT_EOK;
 }
 
 /* SDIO初始化函数 */
 int rt_hw_sdio_init(void)
 {
     static struct stm32_sdio_device sdio_dev;
     HAL_SD_CardInfoTypeDef cardinfo;
     
     /* 初始化HAL SDIO句柄 */
     sdio_dev.hsd.Instance = SDMMC1;
     sdio_dev.hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
     sdio_dev.hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
     sdio_dev.hsd.Init.BusWide = SDMMC_BUS_WIDE_4B;
     sdio_dev.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
     sdio_dev.hsd.Init.ClockDiv = 2;
     
     /* 初始化SDIO外设 */
     if (HAL_SD_Init(&sdio_dev.hsd) != HAL_OK)
     {
         LOG_E("SDIO init failed");
         return -RT_ERROR;
     }
     
     /* 初始化SD卡 */
     if (HAL_SD_InitCard(&sdio_dev.hsd) != HAL_OK)
     {
         LOG_E("SD card init failed");
         return -RT_ERROR;
     }
     
     /* 获取卡信息 */
     if (HAL_SD_GetCardInfo(&sdio_dev.hsd, &cardinfo) != HAL_OK)
     {
         LOG_E("Get SD card info failed");
         return -RT_ERROR;
     }
     
     /* 设置设备参数 */
     sdio_dev.sector_size = cardinfo.LogBlockSize;
     sdio_dev.sector_count = cardinfo.LogBlockNbr;
     
     /* 注册块设备 */
     sdio_dev.parent.type = RT_Device_Class_Block;
     
 #ifdef RT_USING_DEVICE_OPS
     static const struct rt_device_ops sdio_ops = {
         my_rt_sdio_init,
         my_rt_sdio_open,
         my_rt_sdio_close,
         my_rt_sdio_read,
         my_rt_sdio_write,
         my_rt_sdio_control
     };
     sdio_dev.parent.ops = &sdio_ops;
 #else
     sdio_dev.parent.init = my_rt_sdio_init;
     sdio_dev.parent.open = my_rt_sdio_open;
     sdio_dev.parent.close = my_rt_sdio_close;
     sdio_dev.parent.read = my_rt_sdio_read;
     sdio_dev.parent.write = my_rt_sdio_write;
     sdio_dev.parent.control = my_rt_sdio_control;
 #endif
     
     /* 注册设备 */
     rt_device_register(&sdio_dev.parent, "sd0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE);
     
     LOG_I("SDIO init success, block size: %d, block count: %d", 
           sdio_dev.sector_size, sdio_dev.sector_count);
     
     return RT_EOK;
 }
 INIT_DEVICE_EXPORT(rt_hw_sdio_init);